"""The resource management frontend interface"""

import datetime
import re

from django import forms, http
from django.db import IntegrityError
from django.core.urlresolvers import reverse
from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext

from htmock.models import *
from htmock.util.http import *
from htmock.util.restviews import Resource


class NewResourceForm(forms.Form):
    """Form for creating a new resource."""
    label = forms.SlugField(required=False, label=u'Label')
    ttl = forms.FloatField(label=u'Time to live (in hours)', min_value=0.1)
    status = forms.IntegerField(label=u'Response status', min_value=0)
    custom_status = forms.IntegerField(required=False, label=u'Custom status',
                                       min_value=0)
    body = forms.CharField(required=False, label=u'Entity body')
    max_header = forms.IntegerField(min_value=0)
    
    def clean(self):
        data = self.cleaned_data
        if ('status' in data) and ('custom_status' in data) and \
           (data['status'] == 0):
            data['status'] = data['custom_status']
        return data


class InspectIndex(Resource):
    """Index of currently available mock resources."""
    
    def GET(self, request):
        resources = MockResource.objects.all()
        return render_to_response('inspect-index.html',
            { 'resources': resources },
            context_instance=RequestContext(request)
        )
    
    def POST(self, request):
        form = NewResourceForm(request.POST)
        headers = []
        if form.is_valid():
            # Still need to process the headers
            for i in range(form.cleaned_data['max_header'] + 1):
                field_name = request.POST.get('header%d' % i, u'')
                field_value = request.POST.get('value%d' % i, u'')
                if field_name != u'':
                    # See RFC 2616 section 2.2 for the ``token`` production
                    if re.match(u"^[!#\$%&'\*\+\-\.0-9@A-Z\^_`a-z]+$",
                                field_name):
                        headers.append((field_name, field_value))
                    else:
                        return error_to_response(403,
                            '403-invalid-header.html',
                            { 'field_name': field_name }
                        )
        else:
            return error_to_response(403,
                '403-form-errors.html', { 'form': form }
            )
        
        if form.cleaned_data['label'] == u'':
            label = MockResource.random_label()
        else:
            label = form.cleaned_data['label']
        
        resource = MockResource(
            label=label,
            created_on=datetime.datetime.now(),
            alive_until=(datetime.datetime.now() +
                         datetime.timedelta(hours=form.cleaned_data['ttl'])),
            status_code=form.cleaned_data['status'],
            entity_body=form.cleaned_data['body']
        )
        
        try:
            resource.save()
        except IntegrityError:
            return error_to_response(403, '403-error.html', {
                'message': (
                    u'A resource with label <code>%s</code> already exists. ' +
                    u'Please pick another one.'
                ) % resource.label
            })
        
        for field_name, field_value in headers:
            header = Header(resource=resource, field_name=field_name,
                            field_value=field_value)
            header.save()
        
        return HttpResponseSeeOther(reverse('inspect-index'))

class InspectResource(Resource):
    """Management interface to a mock resource."""
    
    def GET(self, request, label):
        resource = get_object_or_404(MockResource, label=label)
        return render_to_response('inspect-resource.html', {
            'resource': resource
        }, context_instance=RequestContext(request))
    
    def DELETE(self, request, label):
        resource = get_object_or_404(MockResource, label=label)
        resource.delete()
        return HttpResponseSeeOther(reverse('inspect-index'))
